package multi_thread.master.lock_aqs;

import multi_thread.advanced.UnsafeParkAndUnPark;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.LockSupport;

/**
 * @author Cheng Jun
 * Description: LockSupport 是JUC中所有锁的底层支持。负责 park 和 unpark 线程。
 * LockSupport的本质是调用 Unsafe类的 park方法将线程状态从 Runnable ==> Waiting
 * LockSupport的本质是调用 Unsafe类的 unpark方法将线程状态从 Waiting ==> Runnable
 * 1 秒 = 1_000_000_000 纳秒(ns)
 * @version 1.0
 * @date 2021/10/25 21:25
 * @see LockSupport
 * @see UnsafeParkAndUnPark
 * @see AbstractQueuedSynchronizer#parkAndCheckInterrupt()
 * @see AbstractQueuedSynchronizer#unparkSuccessor(java.util.concurrent.locks.AbstractQueuedSynchronizer.Node)
 */
public class LockSupportExample {

    public static void main(String[] args) {
        Thread thread0 = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " LockSupport.park() " + "线程阻塞");
            // 阻塞住当前线程
            LockSupport.park();
            // 不能直接这样用，因为在static main 中，且这个是一个函数式接口
            // LockSupport.park(this);
            // 一个 unpark 只能解一次 park，再次调用park 还是造成阻塞。
            // LockSupport.park();
            // 阻塞当前线程2秒
            // LockSupport.parkNanos(10_000_000_000L);
            System.out.println(Thread.currentThread().getName() + " 线程结束");
        });
        thread0.start();

        // new Thread(new Runnable() {
        //     @Override
        //     public void run() {
        //         LockSupport.park(this);
        //     }
        // });

        try {
            // 通过改变 睡眠时间 控制 unpark 和park 的执行顺序。都能正常执行完
            // 先调用 unpark， 再调用 park，park也不会阻塞，但是后续的park 会阻塞。而且先调用多次 unpark 和 先调用一次unpark 效果相同
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // This operation is not guaranteed to have any effect at all if the given thread has not been started.
        // 注意:如果unpark的线程没有启动,是没有任何效果的.
        LockSupport.unpark(thread0);
        // interrupt() 可以让 park() 被中断，但是不会抛出中断异常，同样，不会清除中断标志位
        // thread0.interrupt();
    }
}
